package uy.org.softtech.cssuite.entidad.cliente;

import static javax.xml.bind.annotation.XmlAccessType.FIELD;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import uy.org.softtech.cssuite.entidad.Entidad;
import uy.org.softtech.cssuite.entidad.finanzas.Cuenta;

/**
 * Clase abstracta que contiene la definición de los campos comunes a todos los clientes.
 *
 * @author fabian.lobo
 */
@DiscriminatorColumn(name = "TIPO", discriminatorType = DiscriminatorType.STRING , length = 10)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "CSS_CLIENTE")
@XmlAccessorType(FIELD)
@XmlTransient
public abstract class Cliente extends Entidad {
	
	/**
	 * Enumerado para agrupar los tipos de clientes
	 * 
	 * @author fabian.lobo
	 */
	@XmlEnum
	@XmlType(name = "tipoCliente", namespace = CLIENTE_NAMESPACE)
	public enum Tipo {
		PERSONA, EMPRESA
	}
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "ID_CLIENTE")
	@XmlElement(name = "id", namespace = CLIENTE_NAMESPACE, required = true)
	private Long id;
	
	@Column(name = "TIPO", length = 10, nullable = false, insertable = false, updatable = false)
	@Enumerated(EnumType.STRING)
	@XmlTransient
	private Tipo tipo;
	
	@Column(name = "ELIMINADO")
	@JsonIgnore
	@XmlTransient
	private boolean eliminado;
	
	@Column(name = "BLOQUEADO")
	@XmlElement(name = "bloqueado", namespace = CLIENTE_NAMESPACE, required = true)
	private boolean bloqueado;
	
	@Column(name = "COMENTARIOS", length = 500, nullable = true)
	@XmlElement(name = "comentarios", namespace = CLIENTE_NAMESPACE, required = false)
	private String comentarios;
	
	@Fetch(FetchMode.SUBSELECT)
	@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "cliente")
	@OrderBy(value = "id DESC")
	@XmlElementWrapper(name = "cuentas", namespace = CLIENTE_NAMESPACE, required = true, nillable = false)
	@XmlElement(name = "cuenta", type = Cuenta.class)
	private Set<Cuenta> cuentas;
	
	/*
	 *  GETTERS
	 */
	public Long getId() {
		return id;
	}
	public Tipo getTipo() {
		return tipo;
	}
	public boolean isEliminado() {
		return eliminado;
	}
	public boolean isBloqueado() {
		return bloqueado;
	}
	public String getComentarios() {
		return comentarios;
	}
	public Set<Cuenta> getCuentas() {
		return cuentas;
	}
	
	/*
	 *  SETTERS
	 */
	public void setId(Long id) {
		this.id = id;
	}
	public void setTipo(Tipo tipo) {
		this.tipo = tipo;
	}
	public void setEliminado(boolean eliminado) {
		this.eliminado = eliminado;
	}
	public void setBloqueado(boolean bloqueado) {
		this.bloqueado = bloqueado;
	}
	public void setComentarios(String comentarios) {
		this.comentarios = comentarios;
	}
	public void setCuentas(Set<Cuenta> cuentas) {
		this.cuentas = cuentas;
	}
	
	//@XmlID
	public String convierteId() {
		return getId() != null ? Long.toString(getId()) : "";
	}
	
	@Override
	public abstract int hashCode();

	@Override
	public abstract boolean equals(Object obj);

	@Override
	public abstract String toString();

	@Override
	public abstract String toString(boolean incluirColecciones);

}
